"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StructParser = void 0;
var path_1 = __importDefault(require("path"));
var xml_js_1 = __importDefault(require("xml-js"));
var vendor_1 = require("../tools/vendor");
var def_1 = require("./def");
var StructParser = /** @class */ (function () {
    function StructParser() {
        this.m_structDefMap = {};
        this.m_cliStructs = [];
        this.m_macroFileMap = {};
    }
    Object.defineProperty(StructParser, "Instance", {
        get: function () {
            if (!StructParser.ins)
                StructParser.ins = new StructParser();
            return StructParser.ins;
        },
        enumerable: false,
        configurable: true
    });
    StructParser.prototype.readStructs = function (root) {
        var files = (0, vendor_1.findFiles)(root, ['.xml'], '+');
        for (var _i = 0, files_1 = files; _i < files_1.length; _i++) {
            var f = files_1[_i];
            if (f.endsWith('AdditionalMember.xml'))
                continue;
            this.readStructFile(f, false);
        }
        // 再附加AdditionalMember.xml
        this.readStructFile(path_1.default.join(root, 'AdditionalMember.xml'), true);
        return this.m_cliStructs.sort();
    };
    StructParser.prototype.readStructFile = function (f, isAdditional) {
        // console.log(`reading struct from ${f}`);
        var fileContent = (0, vendor_1.readGB2312)(f);
        var xml = xml_js_1.default.xml2json(fileContent, { compact: true, spaces: 0 });
        var obj = JSON.parse(xml);
        // 1_ConvList.xml 这个文件还有人改名字
        if (!obj.metalib)
            return;
        var fileName = path_1.default.basename(f);
        if (obj.metalib.struct) {
            if (obj.metalib.struct instanceof Array) {
                for (var _i = 0, _a = obj.metalib.struct; _i < _a.length; _i++) {
                    var m = _a[_i];
                    this.addStruct(m, isAdditional, fileName);
                }
            }
            else {
                this.addStruct(obj.metalib.struct, isAdditional, fileName);
            }
        }
        if (obj.metalib.macro) {
            if (obj.metalib.macro instanceof Array) {
                for (var _b = 0, _c = obj.metalib.macro; _b < _c.length; _b++) {
                    var m = _c[_b];
                    this.addMacro(m, fileName);
                }
            }
            else {
                this.addMacro(obj.metalib.macro, fileName);
            }
        }
    };
    StructParser.prototype.addStruct = function (structDef, isAdditional, fromFile) {
        var n = structDef._attributes.name;
        var isCliStruct = false;
        if (structDef._attributes.rootflag && n.endsWith('_Flash')) {
            isCliStruct = true;
        }
        var entries;
        if (structDef.entry instanceof Array) {
            entries = structDef.entry;
        }
        else {
            entries = [structDef.entry];
        }
        var oldDef = this.m_structDefMap[n];
        if (oldDef) {
            if (isAdditional) {
                for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
                    var e = entries_1[_i];
                    e.isAdditional = true;
                    if (!(oldDef.def.entry instanceof Array)) {
                        oldDef.def.entry = [oldDef.def.entry];
                    }
                    oldDef.def.entry.push(e);
                    if ((0, def_1.isComplexType)(e._attributes.type)) {
                        if (isCliStruct && (0, def_1.isComplexType)(e._attributes.type)) {
                            this.addCliStruct(e._attributes.type);
                        }
                    }
                }
            }
            else {
                console.warn("[WARNING]Structure redefinition for ".concat(n, ": ").concat(fromFile));
            }
        }
        else {
            this.m_structDefMap[n] = { def: structDef, file: fromFile };
            if (isCliStruct) {
                this.m_cliStructs.push(n);
                for (var _a = 0, entries_2 = entries; _a < entries_2.length; _a++) {
                    var e = entries_2[_a];
                    if ((0, def_1.isComplexType)(e._attributes.type)) {
                        this.addCliStruct(e._attributes.type);
                    }
                }
            }
        }
    };
    StructParser.prototype.addCliStruct = function (structName) {
        if (!this.m_cliStructs.includes(structName)) {
            this.m_cliStructs.push(structName);
        }
    };
    StructParser.prototype.getStructDef = function (structName) {
        var wrap = this.m_structDefMap[structName];
        if (!wrap) {
            console.error('No struct definition!', structName);
            return null;
        }
        return wrap.def;
    };
    StructParser.prototype.mergeStructs = function (a, b) {
        var sa = this.getStructDef(a);
        if (!sa)
            return;
        var sb = this.getStructDef(b);
        if (!sb)
            return;
        var ea = sa.entry instanceof Array ? sa.entry : [sa.entry];
        var eb = sb.entry instanceof Array ? sb.entry : [sb.entry];
        var ema = {};
        var emb = {};
        for (var _i = 0, ea_1 = ea; _i < ea_1.length; _i++) {
            var e = ea_1[_i];
            ema[e._attributes.name] = e;
        }
        for (var _a = 0, eb_1 = eb; _a < eb_1.length; _a++) {
            var e = eb_1[_a];
            emb[e._attributes.name] = e;
        }
        sa.mergedEntries = [];
        sb.mergedEntries = [];
        for (var _b = 0, ea_2 = ea; _b < ea_2.length; _b++) {
            var e = ea_2[_b];
            if (!emb[e._attributes.name]) {
                sb.mergedEntries.push(e);
            }
        }
        for (var _c = 0, eb_2 = eb; _c < eb_2.length; _c++) {
            var e = eb_2[_c];
            if (!ema[e._attributes.name]) {
                sa.mergedEntries.push(e);
            }
        }
    };
    StructParser.prototype.makeStructCode = function (structName) {
        var wrap = this.m_structDefMap[structName];
        if (!wrap) {
            console.error('No struct definition!', structName);
            process.exit(1);
        }
        var def = wrap.def;
        var code = '';
        if (def._attributes.desc) {
            code += "/**".concat(def._attributes.desc, "(defined in ").concat(wrap.file, ")*/\n");
        }
        code += "export interface ".concat(structName.replace('_Flash', 'M'), " {\n");
        var entries = def.entry instanceof Array ? def.entry : [def.entry];
        if (def.mergedEntries) {
            entries = entries.concat(def.mergedEntries);
        }
        for (var _i = 0, entries_3 = entries; _i < entries_3.length; _i++) {
            var e = entries_3[_i];
            if (e._attributes.desc) {
                code += "    /**".concat(e._attributes.desc, "*/\n");
            }
            code += "    ".concat(e._attributes.name, ": ").concat(this.getEntryType(e), ";\n");
        }
        code += '}\n';
        return code;
    };
    StructParser.prototype.getEntryType = function (e) {
        var type = e._attributes.type;
        if (def_1.NumberLike.includes(type)) {
            type = 'number';
        }
        else if (def_1.StringLike.includes(type)) {
            type = 'string';
        }
        else {
            type = type.replace('_Flash', 'M');
        }
        if (e._attributes.count || e._attributes.refer) {
            type += '[]';
        }
        return type;
    };
    StructParser.prototype.addMacro = function (macro, fromFile) {
        var book = this.m_macroFileMap[fromFile];
        if (!book)
            this.m_macroFileMap[fromFile] = book = { map: {}, list: [] };
        var n = macro._attributes.name;
        var old = book.map[n];
        if (old) {
            if (old._attributes.value != macro._attributes.value) {
                console.error("[ERROR]Macro redefinition for ".concat(n, " in ").concat(fromFile, ": ").concat(macro._attributes.value, "(overrided) vs ").concat(old._attributes.value));
            }
            for (var i = book.list.length - 1; i >= 0; i--) {
                if (book.list[i]._attributes.name == n) {
                    book.list.splice(i, 1);
                    break;
                }
            }
        }
        book.list.push(macro);
        book.map[n] = macro;
    };
    StructParser.prototype.getMacrosOfFile = function (fileName) {
        return this.m_macroFileMap[fileName].list;
    };
    return StructParser;
}());
exports.StructParser = StructParser;
